﻿#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

#endregion

namespace Subro.Controls
{
    public partial class ColorPicker : UserControl,ISupportInitialize,INotifyPropertyChanged
    {
        public ColorPicker()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw
                | ControlStyles.UserPaint, true);
            InitializeComponent();
            Color = DefaultColor;
            
        }


        ButtonState state = ButtonState.Normal;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            state = ButtonState.Pushed;
            Invalidate();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (!dropdownshown) dropdownClosed();
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle r = recColor;
            if (state == ButtonState.Pushed) r.Offset(1, 1);
            if (IsTransparant)
            {
                e.Graphics.DrawString("T", Font, Brushes.Black, r);
            }
            else
                e.Graphics.FillRectangle(brush, r);
            e.Graphics.DrawRectangle(penborder, r);
            ControlPaint.DrawComboButton(
                e.Graphics,
                recButton,
                state);
        }

        bool dropdownshown;
        protected override void OnClick(EventArgs e)
        {
            if (!dropdownshown)
            {
                dropdownshown = true;
                DropDown dropdown = new DropDown(this);
                dropdown.Color = Color;
                dropdown.Show();
            }                
        }

        void dropdownClosed()
        {
            dropdownshown = false;
            state = ButtonState.Normal;
            Invalidate();
        }

        /// <summary>
        /// DropDown form: shown when the main controls dropdown arrow is pressed
        /// </summary>
        class DropDown:Form
        {
            ColorPicker owner;
            ListBox lbColors = new ListBox();
            LinkLabel more = new LinkLabel();
            LinkLabel setrans = new LinkLabel();
            LinkLabel cancel = new LinkLabel();
            public DropDown(ColorPicker owner)
            {
                this.owner = owner;
                ShowInTaskbar = false;
                ControlBox = false;
                FormBorderStyle = FormBorderStyle.FixedToolWindow;
                StartPosition = FormStartPosition.Manual;
                Padding = new Padding(1);

                Rectangle r = owner.RectangleToScreen(new Rectangle(Point.Empty, owner.Size));
                Bounds = new Rectangle(r.Left, r.Top + r.Height, 125, 150);

                lbColors.DataSource = Enum.GetValues(typeof(KnownColor));
                AddControl(lbColors,DockStyle.Fill);
                lbColors.CreateControl();
                lbColors.Click += new EventHandler(lbColors_Click);
                lbColors.DoubleClick += new EventHandler(lbColors_DoubleClick);
                lbColors.KeyDown += new KeyEventHandler(lbColors_KeyDown);
                lbColors.DrawMode = DrawMode.OwnerDrawFixed;
                lbColors.DrawItem += new DrawItemEventHandler(lbColors_DrawItem);
                
                more.Text = "more options";
                AddLabel(more);
                more.Click += new EventHandler(more_Click);

                setrans.Text = "set transparant";
                AddLabel(setrans);
                setrans.Click += new EventHandler(setrans_Click);

                cancel.Text = "cancel";
                cancel.Click += new EventHandler(cancel_Click);
                AddLabel(cancel);

                Color = orgcolor = owner.Color;
            }

            void lbColors_DoubleClick(object sender, EventArgs e)
            {
                Close();
            }

            void cancel_Click(object sender, EventArgs e)
            {
                Color = orgcolor;
                Close();
            }

            Brush fontBrush = Brushes.Black;
            void lbColors_DrawItem(object sender, DrawItemEventArgs e)
            {
                Rectangle r = e.Bounds;
                r.Width = 20;
                r.Inflate(0, -1);
                e.DrawBackground();
                KnownColor kc = (KnownColor)lbColors.Items[e.Index];
                Color c = Color.FromKnownColor(kc);
                e.Graphics.FillRectangle(new SolidBrush(c), r);
                e.Graphics.DrawRectangle(Pens.Black, r);
                e.Graphics.DrawString(kc.ToString(), Font, fontBrush, r.Right + 1, r.Top-1);
            }

            void setrans_Click(object sender, EventArgs e)
            {
                lbColors.SelectedItem = KnownColor.Transparent;
                SelectColor();
            }

            void lbColors_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter)
                    SelectColor();
            }
            void SelectColor()
            {
                Color = Color.FromKnownColor((KnownColor)lbColors.SelectedItem);
            }

            void lbColors_Click(object sender, EventArgs e)
            {
                SelectColor();
            }

            /// <summary>
            /// this boolean is set to true while showing the color dialog.
            /// It is used to prevent the dropdown form closing itself
            /// when it loses focus
            /// </summary>
            bool showingdialog;
            void more_Click(object sender, EventArgs e)
            {
                showingdialog = true;
                using (ColorDialog cd = new ColorDialog())
                {
                    cd.Color = Color;
                    cd.FullOpen = true;
                    if (cd.ShowDialog(this) == DialogResult.OK)
                        Color = cd.Color;
                }
                showingdialog = false;
            }

            void AddControl(Control c,DockStyle ds)
            {
                c.Dock = ds;
                Controls.Add(c);
            }
            void AddLabel(Label l)
            {
                l.TextAlign = ContentAlignment.MiddleCenter;
                l.AutoSize = false;
                l.Height = 15;
                AddControl(l, DockStyle.Bottom);
            }

            protected override void OnDeactivate(EventArgs e)
            {
                if(!showingdialog)Close();
            }

            protected override void OnClosed(EventArgs e)
            {
                owner.dropdownClosed();
            }

            private Color orgcolor, color = DefaultBackColor;
            bool transparant;
            public Color Color
            {
                get { return
                    transparant
                    ? Color.Empty
                    : color; }
                set
                {
                    if(!value.IsEmpty)color = value;
                    if (value.IsKnownColor) lbColors.SelectedItem = value.ToKnownColor();
                    transparant = value.IsEmpty;
                    owner.Color = value;
                }
            }

        }

        Rectangle recColor, recButton;
        protected override void OnResize(EventArgs e)
        {
            int l = argb.Right,w = (DisplayRectangle.Width-l)/2 ;
            recColor = new Rectangle(l, 0, w, Height-2);
            recButton = new Rectangle(l + w + 1, 0,w, Height);
            
        }


        SolidBrush brush;
        Pen penborder;
        readonly Color DefaultColor = Color.Black;
        bool settingcolor;
        [Bindable(true)]
        [SettingsBindable(true)]
        public Color Color
        {
            get { return brush.Color; }
            set
            {
                if (settingcolor) return;
                settingcolor = true;

                brush = new SolidBrush(value);
                penborder = new Pen(Color.Black); //<-todo                
                argb.Value = AutoFormatter.html.ColToInt(value);

                Invalidate();
                settingcolor = false;

                if (OnColorChanged != null)
                    OnColorChanged(this, EventArgs.Empty);
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Color"));
            }
        }
        public event EventHandler OnColorChanged;
        bool ShouldSerializeColor()
        {
            return Color != DefaultColor;
        }
        void ResetColor()
        {
            Color = DefaultBackColor;
        }

        public bool IsTransparant
        {
            get { return Color.IsEmpty || Color == Color.Transparent; }
        }

        #region ISupportInitialize Members

        public void BeginInit()
        {
            argb.BeginInit();
        }

        public void EndInit()
        {
            argb.EndInit();
        }

        #endregion

        private void argb_ValueChanged(object sender, EventArgs e)
        {
            if (!settingcolor)
            {
                int c = (int)argb.Value;
                Color = Color.FromArgb(
                    c >> 16, (c >> 8) & 255, c & 255);
            }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
